<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Admin\ForgotPasswordRequest;
use App\Http\Requests\Admin\ResetPasswordRequest;
use App\Models\Admin\CustomerAdmin;
use App\Models\Admin\PanxAdmin;
use App\Models\Admin\StoreAdmin;
use App\Services\Mailer\Admin\PasswordResetMail;
use App\Services\Utils\Uuid;
use Carbon\Carbon;

class ForgotPasswordController extends ApiController
{
    const RESET_PATH_FORMAT = '/web-admin/?%s#/reset-password';

    /**
     * @param ForgotPasswordRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function forgetPassword(ForgotPasswordRequest $request)
    {
        $admin = $this->findAdminByTypeAccount($request);
            $this->checkIsTrue($admin, trans('admin.admin'));
            $this->checkIsTrue($admin->email, trans('admin.admin_email'));

        // 登录账号信息的加密
        $reset_token = sha1(Uuid::generate());
        $admin->update(compact('reset_token'));

        // 邮件有效期的加密 (有效期1天)
        $expired_timestamp = Carbon::tomorrow()->timestamp;

        // 发送邮件
        $this->sendEmail($admin->email, $reset_token, $request->type, $expired_timestamp);

        // 测试环境才返回 reset token，线上只能从邮箱中获取
        if (! config('app.debug')) $reset_token = null;

        $asterisk_email = $admin->asterisk_email;

        return $this->response(compact('expired_timestamp', 'reset_token', 'asterisk_email'));
    }

    /**
     * @param ForgotPasswordRequest $request
     * @return PanxAdmin|CustomerAdmin|StoreAdmin
     */
    private function findAdminByTypeAccount(ForgotPasswordRequest $request)
    {
        switch($request->type)
        {
            case 'panx':
                $admin = PanxAdmin::where('account', $request->account)->first();
                break;
            case 'customer':
                $admin = CustomerAdmin::where('account', $request->account)->first();
                break;
            case 'store':
                $admin = StoreAdmin::where('account', $request->account)->first();
                break;
            default:
                $admin = null;
        }

        return $admin;
    }

    /**
     * @param $email
     * @param $token
     * @param $type
     * @param $expired
     * @return mixed
     */
    private function sendEmail(string $email, string $token,
                               string $type, string $expired): void
    {
        $lang = app()->getLocale();

        $query = http_build_query(compact('token', 'type', 'expired', 'lang'));

        $reset_url = url(sprintf(self::RESET_PATH_FORMAT, $query));

        PasswordResetMail::send($email, $reset_url);
    }

    /**
     * 用 token 与 新密码 来重置旧密码
     *
     * @param ResetPasswordRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function resetPassword(ResetPasswordRequest $request)
    {
        $this->checkIsTrue(
            Carbon::createFromTimestamp($request->expired)->gte(Carbon::now()),
            trans('admin.expired_timestamp')
        );

        $admin = $this->findAdminByTypeToken($request);
            $this->checkIsTrue($admin, trans('admin.invalidate_token'));

        $reset = $admin->update(['password' => $request->password, 'reset_token' => null]);

        return $this->response(compact('reset', 'admin'));
    }

    /**
     * @param ResetPasswordRequest $request
     * @return PanxAdmin|CustomerAdmin|StoreAdmin
     */
    private function findAdminByTypeToken(ResetPasswordRequest $request)
    {
        switch($request->type)
        {
            case 'panx':
                $admin = PanxAdmin::where('reset_token', $request->token)->first();
                break;
            case 'customer':
                $admin = CustomerAdmin::where('reset_token', $request->token)->first();
                break;
            case 'store':
                $admin = StoreAdmin::where('reset_token', $request->token)->first();
                break;
            default:
                $admin = null;
        }

        return $admin;
    }
}
